package msu.ml.tools;

import weka.core.*;
import msu.ml.util.*;
import msu.ml.presentation.*;
import msu.ml.data.level2.*;
import msu.ml.core.*;
import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SweepClassifier extends JPanel implements MouseListener, ActionListener
{
    private Image image;
    private Scan scan;
    private ArrayList<Point> points;
    private ArrayList<Polygon> displayPolygons;
    private ArrayList<Polygon> polygons;
    private String fileName;
    private double zoom;
    private String classification;
    private JTextArea notes;

    public SweepClassifier(String fileName)
    {
        super();

        this.points = new ArrayList<Point>();
        this.polygons = new ArrayList<Polygon>();
        this.displayPolygons = new ArrayList<Polygon>();
        this.fileName = fileName;
        this.zoom = 1.0;
        this.classification = "mixed";

        Volume v = (new VolumeReader(
                    new BlockReader(fileName))).readVolume();
        scan = v.getSweep(0).getScan(0);

        //Pre process raw data
        PreProcessor pp = new PreProcessor();
        pp.setMinRange(20000);
        //pp.setMaxRange(145000);
        scan = pp.process(scan);

        image = ScanRenderer.getImage(scan, new ReflectivityDataProvider(null), 1000, 1000);

        addMouseListener(this);
    }

    private void writeMetaData()
    {
        try
        {
            String metaFileName = fileName.indexOf(".Z") != -1 ? fileName.replaceFirst(".Z","_meta.xml") :
                fileName.replaceFirst(".gz", "_meta.xml");
            String volumeName = (new File(fileName)).getName();

            PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(metaFileName)));

            out.println("<?xml version=\"1.0\"?>");
            out.println("<scan_meta_data volume=\"" + volumeName + "\" scan=\"0\" type=\"" + this.classification + "\" >");
            if(this.classification.equals("mixed"))
            {
                out.println("<classified_regions type=\"non\">");
                for(int i = 0; i < polygons.size(); i++)
                {
                    out.println("<classified_region>");
                    Polygon current = polygons.get(i);
                    for(int j = 0; j < current.npoints; j++)
                    {
                        out.println("<point x=\"" + current.xpoints[j] + "\" y=\"" + current.ypoints[j] + "\" />");
                    }
                    out.println("</classified_region>");
                }
                out.println("</classified_regions>");

            }
            out.println("<notes>");
            out.println(notes.getText());
            out.println("</notes>");
            out.println("</scan_meta_data>");

            out.close();

            ScanDataConverter converter = new ScanDataConverter();
            Instances instances = converter.convertToInstances(fileName, scan);
            int [] classifications = new int[instances.numInstances()];
            for(int i = 0; i < instances.numInstances(); i++)
            {
                Instance data = instances.instance(i);
                classifications[i] = 1;
                if(this.classification.equals("mixed"))
                {
                    for(int j = 0; j < polygons.size(); j++)
                    {
                        if(polygons.get(j).contains(data.value(0), data.value(1)))
                            classifications[i] = 0;
                    }
                }
                else if(this.classification.equals("non"))
                {
                    classifications[i] = 0;
                }
            }

            this.displayPolygons.clear();
            this.polygons.clear();
            this.points.clear();
            image = ScanRenderer.getImage(instances, 
                classifications, 1000, 1000);

            repaint();
                    
            /*ScanDataConverter converter = new ScanDataConverter();
            Instances instances = converter.convertToInstances(fileName, scan);
            int [] classifications = new int[instances.numInstances()];

            PrintWriter out = new PrintWriter(new BufferedWriter(
                        new FileWriter(fileName + ".cl")));

            for(int i = 0; i < instances.numInstances(); i++)
            {
                Instance data = instances.instance(i);
                classifications[i] = 1;
                for(int j = 0; j < polygons.size(); j++)
                {
                    if(polygons.get(j).contains(data.value(0), data.value(1)))
                        classifications[i] = 0;
                }
                out.println(classifications[i]);
            }

            out.close(); 

            this.displayPolygons.clear();
            this.polygons.clear();
            this.points.clear();
            image = ScanRenderer.getImage(instances, classifications, 1000, 1000);*/

            JOptionPane.showMessageDialog(this, "Meta data written to " + metaFileName);
        }
        catch(Exception ex)
        {
            System.out.println(ex.getMessage());
            ex.printStackTrace();
        }

    }

    public double getZoom()
    {
        return this.zoom;
    }

    public void setZoom(double value)
    {
        this.zoom = value;
    }

    public void setNotes(JTextArea value)
    {
        this.notes = value;
    }

    public void paintComponent(Graphics g)
    {
        int width = (int)((double)image.getWidth(null) * zoom);
        int height = (int)((double)image.getHeight(null) * zoom);
        g.drawImage(image, 0, 0, width, height, null);
        for(int i = 0; i < displayPolygons.size(); i++)
        {
            g.setColor(Color.RED);
            g.drawPolygon(displayPolygons.get(i));
        }

        for(int i = 0; i < points.size(); i++)
        {
            Point p = points.get(i);
            g.setColor(Color.RED);
            g.fillOval(p.x, p.y, 5, 5);
            if(i > 0)
            {
                Point prev = points.get(i - 1);
                g.setColor(Color.BLACK);
                g.drawLine(prev.x, prev.y, p.x, p.y);
            }
        }
    }

    public void actionPerformed(ActionEvent e)
    {
        if(e.getActionCommand().equals("Zoom In"))
        {
            this.zoom += .25;
            if(this.zoom > 3.0)
                this.zoom = 3.0;
        }
        else if(e.getActionCommand().equals("Zoom Out"))
        {
            this.zoom -= .25;
            if(this.zoom < .25)
                this.zoom = .25;
        }
        else if(e.getActionCommand().equals("Biological"))
        {
            this.classification = "bio";
        }
        else if(e.getActionCommand().equals("Non-Biological"))
        {
            this.classification = "non";
        }
        else if(e.getActionCommand().equals("Mixed"))
        {
            this.classification = "mixed";
        }
        else if(e.getActionCommand().equals("Clear"))
        {
            this.displayPolygons.clear();
            this.polygons.clear();
            this.points.clear();
        }
        else if(e.getActionCommand().equals("Add"))
        {
            int [] x = new int[points.size()];
            int [] y = new int[points.size()];

            for(int i = 0; i < points.size(); i++)
            {
                x[i] = points.get(i).x;
                y[i] = points.get(i).y;
            }

            this.displayPolygons.add(new Polygon(x, y, points.size()));

            for(int i = 0; i < points.size(); i++)
            {
                x[i] = points.get(i).x - 500;
                y[i] = (1000 - points.get(i).y) - 500;
            }

            this.polygons.add(new Polygon(x, y, points.size()));
            points.clear();
        }
        else if(e.getActionCommand().equals("Done"))
        {
            writeMetaData();
        }
        repaint();
    }

    public void mousePressed(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mouseClicked(MouseEvent e) 
    {
        if(this.classification.equals("mixed"))
            points.add(e.getPoint());
        repaint();
    }

    public static void main(String [] args) throws Exception
    {

        SweepClassifier classifier = new SweepClassifier(args[0]);

        JButton doneButton = new JButton("Done");
        doneButton.addActionListener(classifier);
        JButton addButton = new JButton("Add");
        addButton.addActionListener(classifier);
        JButton clearButton = new JButton("Clear");
        clearButton.addActionListener(classifier);

        JButton zoomInButton = new JButton("Zoom In");
        zoomInButton.setEnabled(false);
        zoomInButton.addActionListener(classifier);
        JButton zoomOutButton = new JButton("Zoom Out");
        zoomOutButton.setEnabled(false);
        zoomOutButton.addActionListener(classifier);

        JRadioButton bioRadioButton = new JRadioButton("Biological");
        bioRadioButton.addActionListener(classifier);
        JRadioButton nonRadioButton = new JRadioButton("Non-Biological");
        nonRadioButton.addActionListener(classifier);
        JRadioButton mixedRadioButton = new JRadioButton("Mixed");
        mixedRadioButton.addActionListener(classifier);

        ButtonGroup classGroup = new ButtonGroup();
        classGroup.add(bioRadioButton);
        classGroup.add(nonRadioButton);
        classGroup.add(mixedRadioButton);

        mixedRadioButton.setSelected(true);

        JPanel classPanel = new JPanel();
        classPanel.add(new JLabel("Class "));
        classPanel.add(bioRadioButton);
        classPanel.add(nonRadioButton);
        classPanel.add(mixedRadioButton);

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(classPanel);
        buttonPanel.add(addButton);
        buttonPanel.add(clearButton);
        buttonPanel.add(zoomInButton);
        buttonPanel.add(zoomOutButton);

        JTextArea notesArea = new JTextArea();
        notesArea.setColumns(40);
        classifier.setNotes(notesArea);

        JPanel notesPanel = new JPanel();
        notesPanel.setLayout(new BoxLayout(notesPanel, BoxLayout.PAGE_AXIS));
        notesPanel.setBorder(BorderFactory.createEmptyBorder(10,0,10,10));
        notesPanel.add(new JLabel("Notes"));
        notesPanel.add(Box.createRigidArea(new Dimension(0,5)));
        notesPanel.add(notesArea);

        JScrollPane classifierPane = new JScrollPane(classifier);
        classifierPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));

        JFrame f = new JFrame("Scan Classifier");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(1200, 700);
        classifier.setMinimumSize(new Dimension(1000, 1000));
        classifier.setPreferredSize(new Dimension(1000, 1000));
        f.setLocation(50, 50);
        f.getContentPane().add(BorderLayout.CENTER, classifierPane);
        //f.getContentPane().add(BorderLayout.NORTH, addButton);
        f.getContentPane().add(BorderLayout.NORTH, buttonPanel);
        f.getContentPane().add(BorderLayout.SOUTH, doneButton);
        f.getContentPane().add(BorderLayout.EAST, notesPanel);
        //f.getContentPane().add(BorderLayout.WEST, clearButton);
        f.setVisible(true);
    }
}
